/*文件工具类*/
#pragma once
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <memory>
#include <cstdio>
#include <experimental/filesystem>
#include <jsoncpp/json/json.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "bundle.h"

namespace cloud
{
    namespace fs = std::experimental::filesystem;
    class UtilFile
    {
    public:
        UtilFile(std::string filename)
            : _filename(filename)
        {
        }

        void removeFile() { remove(_filename.c_str());}

        size_t fileSize()
        {
            struct stat buf;
            if (stat(_filename.c_str(), &buf) < 0)
            {
                std::cout << "Get file size fail!" << std::endl;
                return -1;
            }

            return buf.st_size;
        }

        time_t lastModtime()
        {
            struct stat buf;
            if (stat(_filename.c_str(), &buf) < 0)
            {
                std::cout << "Get time of last modification fail!" << std::endl;
                return -1;
            }

            return buf.st_mtime;
        }

        time_t lastAcctime()
        {
            struct stat buf;
            if (stat(_filename.c_str(), &buf) < 0)
            {
                std::cout << "Get time of last access fail!" << std::endl;
                return -1;
            }

            return buf.st_atime;
        }

        std::string fileName()
        {
            // 存在性判断
            size_t pos = _filename.rfind("/");
            if (pos == std::string::npos)
                return _filename.c_str();

            return _filename.substr(pos + 1);
        }

        bool getPosLen(std::string &body, size_t pos, size_t len) // 用来实现断点续传
        {
            if (pos + len > fileSize())
                return false;

            std::ifstream ifs;
            ifs.open(_filename.c_str(), std::ios::binary);
            if (ifs.good() == false)
            {
                std::cout << "read open file fail!" << std::endl;
                return false;
            }

            ifs.seekg(pos, std::ios::beg);
            body.resize(len);
            ifs.read(&body[0], len);
            ifs.close();
            return true;
        }

        bool setContent(const std::string &body)
        {
            std::ofstream ofs;
            ofs.open(_filename.c_str(), std::ios::binary);
            if (ofs.is_open() == false)
            {
                std::cout << "write open file fail!" << std::endl;
                return false;
            }

            ofs.write(&body[0], body.size());
            if (ofs.good() == false)
            {
                std::cout << "write file content fail!" << std::endl;
                ofs.close();
            }
            ofs.close();
            return true;
        }

        bool getContent(std::string &body)
        {
            return getPosLen(body, 0, fileSize());
        }

        bool compress(const std::string &packname)
        {
            std::string body;
            // 获取压缩文件内容
            if (getContent(body) == false)
            {
                std::cout << "compress get file fail!" << std::endl;
                return false;
            }
            // 压缩文件
            std::string pack = bundle::pack(bundle::LZIP, body);
            UtilFile file(packname);
            // 写入压缩内容
            if (file.setContent(pack) == false)
            {
                std::cout << "compress set pack content fail!" << std::endl;
                return false;
            }

            return true;
        }

        bool uncompress(const std::string &unpackname)
        {
            std::string body;
            // 获取解压文件内容
            if (getContent(body) == false)
            {
                std::cout << "uncompress get file fail!" << std::endl;
                return false;
            }
            // 解压文件
            std::string unpack = bundle::unpack(body);
            UtilFile file(unpackname);
            // 写入解压内容
            if (file.setContent(unpack) == false)
            {
                std::cout << "uncompress set unpack content fail!" << std::endl;
                return false;
            }

            return true;
        }

        bool exists()
        {
            return fs::exists(_filename);
        }

        bool createDirectory()
        {
            if(exists()) return true;
            return fs::create_directories(_filename);
        }

        bool sanDirectory(std::vector<std::string> &arry)
        {
            // 利用库的迭代器，遍历该目录下的所有文件
            for(auto &p : fs::directory_iterator(_filename))
            {
                if(fs::is_directory(p)) continue;
                // relative_path: 带有路径的文件名
                arry.push_back(fs::path(p).relative_path().string()); 
            }

            return true;
        }

    private:
        std::string _filename;
    };

    class JosnUtil
    {
    public:
        static bool serialize(const Json::Value &root, std::string &str)
        {
            Json::StreamWriterBuilder swb;
            std::unique_ptr<Json::StreamWriter> sw_ptr(swb.newStreamWriter());
            std::stringstream ss;

            if(sw_ptr->write(root, &ss) != 0)
            {
                std::cout << "serialize fail!" << std::endl;
                return false;
            }
            str = ss.str();
            return true;
        }

        static bool unserialize(const std::string &str, Json::Value &root)
        {
            Json::CharReaderBuilder crb;
            std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
            std::string err;
            bool ret = cr->parse(&str[0], &str[0] + str.size(), &root, &err);

            if(ret == false)
            {
                std::cout << "unserialize fail, err: " << err << std::endl;
                return false;
            }
            return true;
        }
    };
}